<?php
/*
* Copyright 2017 Baidu, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* Http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/

namespace BaiduBce\Services\Blb;

use BaiduBce\Auth\BceV1Signer;
use BaiduBce\BceBaseClient;
use BaiduBce\Http\BceHttpClient;
use BaiduBce\Http\HttpHeaders;
use BaiduBce\Http\HttpMethod;
use BaiduBce\Http\HttpContentTypes;
use BaiduBce\Services\Blb\model\BackendServer;

/**
 * This module provides a client class for BLB.
 */
class BlbClient extends BceBaseClient
{

    private $signer;
    private $httpClient;
    private $prefix = '/v1';

    /**
     * The BlbClient constructor.
     *
     * @param array $config The client configuration
     */
    function __construct(array $config)
    {
        parent::__construct($config, 'blb');
        $this->signer = new BceV1Signer();
        $this->httpClient = new BceHttpClient();
    }

    /**
     * Create an nat with the specified options.
     *
     * @param string $name
     *          name of nat
     *
     * @param string $vpcId
     *          id of vpc which nat created in
     *
     * @param string $subnetId
     *          id of subnet which blb created in
     *
     * @param string $desc
     *          description of blb
     *
     * @param string $clientToken
     *          if the clientToken is not specified by the user, a random String
     *          generated by default algorithm will be used.
     *
     * @param array $options
     *          The optional bce configuration, which will overwrite the
     *          default configuration that was passed while creating EipClient instance.
     *
     * @return mixed
     */
    public function createBlb($vpcId = null, $subnetId = null, $name = null, $desc = null, $clientToken = null, $options = array())
    {
        list($config) = $this->parseOptions($options, 'config');
        $body = array();
        if ($vpcId !== null) {
            $body['vpcId'] = $vpcId;
        }
        if ($subnetId !== null) {
            $body['subnetId'] = $subnetId;
        }
        if ($name !== null) {
            $body['name'] = $name;
        }
        if ($desc !== null) {
            $body['desc'] = $desc;
        }
        $body['end'] = '';
        $params = array();
        if (empty($clientToken)) {
            $params['clientToken'] = $this->generateClientToken();
        } else {
            $params['clientToken'] = $clientToken;
        }

        return $this->sendRequest(
            HttpMethod::POST,
            array(
                'config' => $config,
                'params' => $params,
                'body' => json_encode($body),
            ),
            '/blb'
        );
    }

    /**
     * get a list of blb owned by the authenticated user and specified conditions.
     *
     * @param string $address
     *          address of blb in vpc. The optional parameter
     *
     * @param string $blbId
     *          id of blb instance. The optional parameter
     *
     * @param string $name
     *          name of nat instance. The optional parameter
     *
     * @param string $bccId
     *          id of bcc instance which is bound to blb instance. The optional parameter
     *
     * @param string $marker
     *          The optional parameter marker specified in the original request to specify
     *          where in the results to begin listing.
     *
     * @param int $maxKeys
     *          The optional parameter to specifies the max number of list result to return.
     *          The default value is 1000.
     *
     * @param array $options
     *           The optional bce configuration, which will overwrite the
     *          default configuration that was passed while creating EipClient instance.
     *
     * @return mixed
     */
    public function listBlbs($address = null, $name = null, $blbId = null, $bccId = null, $marker = null, $maxKeys = 1000, $options = array())
    {
        list($config) = $this->parseOptions($options, 'config');
        $params = array();
        if ($address !== null) {
            $params['address'] = $address;
        }
        if ($blbId !== null) {
            $params['blbId'] = $blbId;
        }
        if ($name !== null) {
            $params['name'] = $name;
        }
        if ($bccId !== null) {
            $params['bccId'] = $bccId;
        }
        if ($marker !== null) {
            $params['marker'] = $marker;
        }
        if ($maxKeys !== null) {
            $params['maxKeys'] = $maxKeys;
        }

        return $this->sendRequest(
            HttpMethod::GET,
            array(
                'config' => $config,
                'params' => $params,
            ),
            '/blb'
        );
    }

    /**
     * update single blb
     *
     * @param string $blbId
     *          id of blb instance
     *
     * @param string $name
     *          name of blb instance to be updated
     *
     * @param string $desc
     *          description of blb instance to be updated
     *
     * @param string $clientToken
     *          if the clientToken is not specified by the user, a random String
     *          generated by default algorithm will be used.
     *
     * @param array $options
     *          The optional bce configuration, which will overwrite the
     *          default configuration that was passed while creating EipClient instance.
     *
     * @return mixed
     */
    public function updateBlb($blbId, $name = null, $desc = null, $clientToken = null, $options = array())
    {
        list($config) = $this->parseOptions($options, 'config');
        $body = array();
        if ($name !== null) {
            $body['name'] = $name;
        }
        if ($desc !== null) {
            $body['desc'] = $desc;
        }
        $params = array();
        if (empty($clientToken)) {
            $clientToken = $this->generateClientToken();
        }
        $params['clientToken'] = $clientToken;

        return $this->sendRequest(
            HttpMethod::PUT,
            array(
                'config' => $config,
                'params' => $params,
                'body' => json_encode($body),
            ),
            '/blb/' . $blbId
        );
    }

    /**
     * delete the blb
     * Only the Postpaid instance or Prepaid which is expired can be released.
     *
     * @param string $blbId
     *          id of blb instance to be released
     *
     * @param string $clientToken
     *          if the clientToken is not specified by the user, a random String
     *          generated by default algorithm will be used.
     *
     * @param array $options
     *          The optional bce configuration, which will overwrite the
     *          default configuration that was passed while creating EipClient instance.
     *
     * @return mixed
     */
    public function deleteBlb($blbId, $clientToken = null, $options = array())
    {
        list($config) = $this->parseOptions($options, 'config');
        if (empty($clientToken)) {
            $clientToken = $this->generateClientToken();
        }
        $params = array();
        $params['clientToken'] = $clientToken;

        return $this->sendRequest(
            HttpMethod::DELETE,
            array(
                'config' => $config,
                'params' => $params,
            ),
            '/blb/' . $blbId
        );
    }

    /**
     * Create a tcp listener with the specified options.
     *
     * @param string $blbId
     *          id of blb
     *
     * @param int $listenerPort
     *          front end port of listener
     *
     * @param int $backendPort
     *          back end port of listener
     *
     * @param string $scheduler
     *          scheduler of load balance
     *
     * @param int $healthCheckTimeoutInSecond
     *          timeout of health check, default 3 seconds
     *
     * @param int $healthCheckInterval
     *          interval of health check, default 3 seconds
     *
     * @param int $unhealthyThreshold
     *          times threshold of unhealthy check, default 3 times
     *
     * @param int $healthyThreshold
     *          times threshold of healthy check, default 3 times
     *
     * @param string $clientToken
     *          if the clientToken is not specified by the user, a random String
     *          generated by default algorithm will be used.
     *
     * @param array $options
     *          The optional bce configuration, which will overwrite the
     *          default configuration that was passed while creating EipClient instance.
     *
     * @return mixed
     */
    public function createTcpListener($blbId, $listenerPort, $backendPort, $scheduler, $healthCheckTimeoutInSecond = 3, $healthCheckInterval = 3, $unhealthyThreshold = 3, $healthyThreshold = 3, $clientToken = null, $options = array())
    {
        list($config) = $this->parseOptions($options, 'config');
        $body = array();
        $body['listenerPort'] = $listenerPort;
        $body['backendPort'] = $backendPort;
        $body['scheduler'] = $scheduler;
        $body['healthCheckTimeoutInSecond'] = $healthCheckTimeoutInSecond;
        $body['healthCheckInterval'] = $healthCheckInterval;
        $body['unhealthyThreshold'] = $unhealthyThreshold;
        $body['healthyThreshold'] = $healthyThreshold;
        $params = array();
        if (empty($clientToken)) {
            $params['clientToken'] = $this->generateClientToken();
        } else {
            $params['clientToken'] = $clientToken;
        }

        return $this->sendRequest(
            HttpMethod::POST,
            array(
                'config' => $config,
                'params' => $params,
                'body' => json_encode($body),
            ),
            '/blb/' . $blbId . '/TCPlistener'
        );
    }

    /**
     * Create a udp listener with the specified options.
     *
     * @param string $blbId
     *          id of blb
     *
     * @param int $listenerPort
     *          front end port of listener
     *
     * @param int $backendPort
     *          back end port of listener
     *
     * @param string $scheduler
     *          scheduler of load balance
     *
     * @param string $healthCheckString
     *          string to send for health check
     *
     * @param int $healthCheckTimeoutInSecond
     *          timeout of health check, default 3 seconds
     *
     * @param int $healthCheckInterval
     *          interval of health check, default 3 seconds
     *
     * @param int $unhealthyThreshold
     *          times threshold of unhealthy check, default 3 times
     *
     * @param int $healthyThreshold
     *          times threshold of healthy check, default 3 times
     *
     * @param string $clientToken
     *          if the clientToken is not specified by the user, a random String
     *          generated by default algorithm will be used.
     *
     * @param array $options
     *          The optional bce configuration, which will overwrite the
     *          default configuration that was passed while creating EipClient instance.
     *
     * @return mixed
     */
    public function createUdpListener($blbId, $listenerPort, $backendPort, $scheduler, $healthCheckString, $healthCheckTimeoutInSecond = 3, $healthCheckInterval = 3, $unhealthyThreshold = 3, $healthyThreshold = 3, $clientToken = null, $options = array())
    {
        list($config) = $this->parseOptions($options, 'config');
        $body = array();
        $body['listenerPort'] = $listenerPort;
        $body['backendPort'] = $backendPort;
        $body['scheduler'] = $scheduler;
        $body['healthCheckString'] = $healthCheckString;
        $body['healthCheckTimeoutInSecond'] = $healthCheckTimeoutInSecond;
        $body['healthCheckInterval'] = $healthCheckInterval;
        $body['unhealthyThreshold'] = $unhealthyThreshold;
        $body['healthyThreshold'] = $healthyThreshold;
        $params = array();
        if (empty($clientToken)) {
            $params['clientToken'] = $this->generateClientToken();
        } else {
            $params['clientToken'] = $clientToken;
        }

        return $this->sendRequest(
            HttpMethod::POST,
            array(
                'config' => $config,
                'params' => $params,
                'body' => json_encode($body),
            ),
            '/blb/' . $blbId . '/UDPlistener'
        );
    }

    /**
     * Create a http listener with the specified options.
     *
     * @param string $blbId
     *          id of blb
     *
     * @param int $listenerPort
     *          front end port of listener
     *
     * @param int $backendPort
     *          back end port of listener
     *
     * @param string $scheduler
     *          scheduler of load balance
     *
     * @param boolean $keepSession
     *          switch for keep session
     *
     * @param string $keepSessionType
     *          type to keep session
     *
     * @param int $keepSessionDuration
     *          duration to keep session
     *
     * @param string $keepSessionCookieName
     *          cookie name for keep session
     *
     * @param boolean $xForwardFor
     *          switch for acquiring real ip
     *
     * @param string $healthCheckType
     *          type for health check
     *
     * @param int $healthCheckPort
     *          port for health check
     *
     * @param string $healthCheckURI
     *          uri for health check
     *
     * @param int $healthCheckTimeoutInSecond
     *          timeout of health check, default 3 seconds
     *
     * @param int $healthCheckInterval
     *          interval of health check, default 3 seconds
     *
     * @param int $unhealthyThreshold
     *          times threshold of unhealthy check, default 3 times
     *
     * @param int $healthyThreshold
     *          times threshold of healthy check, default 3 times
     *
     * @param string $healthCheckNormalStatus
     *          normal status for http health check
     *
     * @param int $serverTimeout
     *          timeout for backend server
     *
     * @param int $redirectPort
     *          port for redirect
     *
     * @param string $clientToken
     *          if the clientToken is not specified by the user, a random String
     *          generated by default algorithm will be used.
     *
     * @param array $options
     *          The optional bce configuration, which will overwrite the
     *          default configuration that was passed while creating EipClient instance.
     *
     * @return mixed
     */
    public function createHttpListener($blbId, $listenerPort, $backendPort, $scheduler, $keepSession = false,
                                       $keepSessionType = null, $keepSessionDuration = 3600, $keepSessionCookieName = null,
                                       $xForwardFor = false, $healthCheckType = null, $healthCheckPort = null, $healthCheckURI = null,
                                       $healthCheckTimeoutInSecond = 3, $healthCheckInterval = 3, $unhealthyThreshold = 3, $healthyThreshold = 3,
                                       $healthCheckNormalStatus = null, $serverTimeout = 30, $redirectPort = null, $clientToken = null, $options = array())
    {
        list($config) = $this->parseOptions($options, 'config');
        $body = array();
        $body['listenerPort'] = $listenerPort;
        $body['backendPort'] = $backendPort;
        $body['scheduler'] = $scheduler;
        if ($keepSession !== null) {
            $body['keepSession'] = $keepSession;
        }
        if ($keepSessionType !== null) {
            $body['keepSessionType'] = $keepSessionType;
        }
        if ($keepSessionDuration !== null) {
            $body['keepSessionDuration'] = $keepSessionDuration;
        }
        if ($keepSessionCookieName !== null) {
            $body['keepSessionCookieName'] = $keepSessionCookieName;
        }
        if ($xForwardFor !== null) {
            $body['xForwardFor'] = $xForwardFor;
        }
        if ($healthCheckType !== null) {
            $body['healthCheckType'] = $healthCheckType;
        }
        if ($healthCheckPort !== null) {
            $body['healthCheckPort'] = $healthCheckPort;
        }
        if ($healthCheckURI !== null) {
            $body['healthCheckURI'] = $healthCheckURI;
        }
        if ($healthCheckNormalStatus !== null) {
            $body['healthCheckNormalStatus'] = $healthCheckNormalStatus;
        }
        if ($serverTimeout !== null) {
            $body['serverTimeout'] = $serverTimeout;
        }
        if ($redirectPort !== null) {
            $body['redirectPort'] = $redirectPort;
        }
        $body['healthCheckTimeoutInSecond'] = $healthCheckTimeoutInSecond;
        $body['healthCheckInterval'] = $healthCheckInterval;
        $body['unhealthyThreshold'] = $unhealthyThreshold;
        $body['healthyThreshold'] = $healthyThreshold;
        $params = array();
        if (empty($clientToken)) {
            $params['clientToken'] = $this->generateClientToken();
        } else {
            $params['clientToken'] = $clientToken;
        }

        return $this->sendRequest(
            HttpMethod::POST,
            array(
                'config' => $config,
                'params' => $params,
                'body' => json_encode($body),
            ),
            '/blb/' . $blbId . '/HTTPlistener'
        );
    }

    /**
     * Create a https listener with the specified options.
     *
     * @param string $blbId
     *          id of blb
     *
     * @param int $listenerPort
     *          front end port of listener
     *
     * @param int $backendPort
     *          back end port of listener
     *
     * @param string $scheduler
     *          scheduler of load balance
     *
     * @param array $certIds
     *          SSL certs for listener
     *
     * @param boolean $keepSession
     *          switch for keep session
     *
     * @param string $keepSessionType
     *          type to keep session
     *
     * @param int $keepSessionDuration
     *          duration to keep session
     *
     * @param string $keepSessionCookieName
     *          cookie name for keep session
     *
     * @param boolean $xForwardFor
     *          switch for acquiring real ip
     *
     * @param string $healthCheckType
     *          type for health check
     *
     * @param int $healthCheckPort
     *          port for health check
     *
     * @param string $healthCheckURI
     *          uri for health check
     *
     * @param int $healthCheckTimeoutInSecond
     *          timeout of health check, default 3 seconds
     *
     * @param int $healthCheckInterval
     *          interval of health check, default 3 seconds
     *
     * @param int $unhealthyThreshold
     *          times threshold of unhealthy check, default 3 times
     *
     * @param int $healthyThreshold
     *          times threshold of healthy check, default 3 times
     *
     * @param string $healthCheckNormalStatus
     *          normal status for http health check
     *
     * @param int $serverTimeout
     *          timeout for backend server
     *
     * @param boolean $ie6Compatible
     *          switch for compatibility with IE6
     *
     * @param string $clientToken
     *          if the clientToken is not specified by the user, a random String
     *          generated by default algorithm will be used.
     *
     * @param array $options
     *          The optional bce configuration, which will overwrite the
     *          default configuration that was passed while creating EipClient instance.
     *
     * @return mixed
     */
    public function createHttpsListener($blbId, $listenerPort, $backendPort, $scheduler, $certIds, $keepSession = false,
                                        $keepSessionType = null, $keepSessionDuration = 3600, $keepSessionCookieName = null,
                                        $xForwardFor = false, $healthCheckType = null, $healthCheckPort = null, $healthCheckURI = null,
                                        $healthCheckTimeoutInSecond = 3, $healthCheckInterval = 3, $unhealthyThreshold = 3, $healthyThreshold = 3,
                                        $healthCheckNormalStatus = null, $serverTimeout = 30, $ie6Compatible = true, $clientToken = null, $options = array())
    {
        list($config) = $this->parseOptions($options, 'config');
        $body = array();
        $body['listenerPort'] = $listenerPort;
        $body['backendPort'] = $backendPort;
        $body['scheduler'] = $scheduler;
        $body['certIds'] = $this->objectToArray($certIds);
        if ($keepSession !== null) {
            $body['keepSession'] = $keepSession;
        }
        if ($keepSessionType !== null) {
            $body['keepSessionType'] = $keepSessionType;
        }
        if ($keepSessionDuration !== null) {
            $body['keepSessionDuration'] = $keepSessionDuration;
        }
        if ($keepSessionCookieName !== null) {
            $body['keepSessionCookieName'] = $keepSessionCookieName;
        }
        if ($xForwardFor !== null) {
            $body['xForwardFor'] = $xForwardFor;
        }
        if ($healthCheckType !== null) {
            $body['healthCheckType'] = $healthCheckType;
        }
        if ($healthCheckPort !== null) {
            $body['healthCheckPort'] = $healthCheckPort;
        }
        if ($healthCheckURI !== null) {
            $body['healthCheckURI'] = $healthCheckURI;
        }
        if ($healthCheckNormalStatus !== null) {
            $body['healthCheckNormalStatus'] = $healthCheckNormalStatus;
        }
        if ($serverTimeout !== null) {
            $body['serverTimeout'] = $serverTimeout;
        }
        if ($ie6Compatible !== null) {
            $body['ie6Compatible'] = $ie6Compatible;
        }
        $body['healthCheckTimeoutInSecond'] = $healthCheckTimeoutInSecond;
        $body['healthCheckInterval'] = $healthCheckInterval;
        $body['unhealthyThreshold'] = $unhealthyThreshold;
        $body['healthyThreshold'] = $healthyThreshold;
        $params = array();
        if (empty($clientToken)) {
            $params['clientToken'] = $this->generateClientToken();
        } else {
            $params['clientToken'] = $clientToken;
        }

        return $this->sendRequest(
            HttpMethod::POST,
            array(
                'config' => $config,
                'params' => $params,
                'body' => json_encode($body),
            ),
            '/blb/' . $blbId . '/HTTPSlistener'
        );
    }

    /**
     * list tcp listener.
     *
     * @param string $blbId
     *          id of blb instance
     *
     * @param int listenerPort
     *          port of listener
     *
     * @param string $marker
     *          The optional parameter marker specified in the original request to specify
     *          where in the results to begin listing.
     *
     * @param int $maxKeys
     *          The optional parameter to specifies the max number of list result to return.
     *          The default value is 1000.
     *
     * @param array $options
     *          The optional bce configuration, which will overwrite the
     *          default configuration that was passed while creating EipClient instance.
     *
     * @return mixed
     */
    public function listTcpListeners($blbId, $listenerPort = null, $marker = null, $maxKeys = 1000, $options = array())
    {
        list($config) = $this->parseOptions($options, 'config');
        $params = array();
        if ($listenerPort !== null) {
            $params['listenerPort'] = $listenerPort;
        }
        if ($marker !== null) {
            $params['marker'] = $marker;
        }
        if ($maxKeys !== null) {
            $params['maxKeys'] = $maxKeys;
        }

        return $this->sendRequest(
            HttpMethod::GET,
            array(
                'config' => $config,
                'params' => $params,
            ),
            '/blb/' . $blbId . '/TCPlistener'
        );
    }

    /**
     * list udp listener.
     *
     * @param string $blbId
     *          id of blb instance
     *
     * @param int listenerPort
     *          port of listener
     *
     * @param string $marker
     *          The optional parameter marker specified in the original request to specify
     *          where in the results to begin listing.
     *
     * @param int $maxKeys
     *          The optional parameter to specifies the max number of list result to return.
     *          The default value is 1000.
     *
     * @param array $options
     *          The optional bce configuration, which will overwrite the
     *          default configuration that was passed while creating EipClient instance.
     *
     * @return mixed
     */
    public function listUdpListeners($blbId, $listenerPort = null, $marker = null, $maxKeys = 1000, $options = array())
    {
        list($config) = $this->parseOptions($options, 'config');
        $params = array();
        if ($listenerPort !== null) {
            $params['listenerPort'] = $listenerPort;
        }
        if ($marker !== null) {
            $params['marker'] = $marker;
        }
        if ($maxKeys !== null) {
            $params['maxKeys'] = $maxKeys;
        }

        return $this->sendRequest(
            HttpMethod::GET,
            array(
                'config' => $config,
                'params' => $params,
            ),
            '/blb/' . $blbId . '/UDPlistener'
        );
    }

    /**
     * list http listener.
     *
     * @param string $blbId
     *          id of blb instance
     *
     * @param int listenerPort
     *          port of listener
     *
     * @param string $marker
     *          The optional parameter marker specified in the original request to specify
     *          where in the results to begin listing.
     *
     * @param int $maxKeys
     *          The optional parameter to specifies the max number of list result to return.
     *          The default value is 1000.
     *
     * @param array $options
     *          The optional bce configuration, which will overwrite the
     *          default configuration that was passed while creating EipClient instance.
     *
     * @return mixed
     */
    public function listHttpListeners($blbId, $listenerPort = null, $marker = null, $maxKeys = 1000, $options = array())
    {
        list($config) = $this->parseOptions($options, 'config');
        $params = array();
        if ($listenerPort !== null) {
            $params['listenerPort'] = $listenerPort;
        }
        if ($marker !== null) {
            $params['marker'] = $marker;
        }
        if ($maxKeys !== null) {
            $params['maxKeys'] = $maxKeys;
        }

        return $this->sendRequest(
            HttpMethod::GET,
            array(
                'config' => $config,
                'params' => $params,
            ),
            '/blb/' . $blbId . '/HTTPlistener'
        );
    }

    /**
     * list https listener.
     *
     * @param string $blbId
     *          id of blb instance
     *
     * @param int listenerPort
     *          port of listener
     *
     * @param string $marker
     *          The optional parameter marker specified in the original request to specify
     *          where in the results to begin listing.
     *
     * @param int $maxKeys
     *          The optional parameter to specifies the max number of list result to return.
     *          The default value is 1000.
     *
     * @param array $options
     *          The optional bce configuration, which will overwrite the
     *          default configuration that was passed while creating EipClient instance.
     *
     * @return mixed
     */
    public function listHttpsListeners($blbId, $listenerPort = null, $marker = null, $maxKeys = 1000, $options = array())
    {
        list($config) = $this->parseOptions($options, 'config');
        $params = array();
        if ($listenerPort !== null) {
            $params['listenerPort'] = $listenerPort;
        }
        if ($marker !== null) {
            $params['marker'] = $marker;
        }
        if ($maxKeys !== null) {
            $params['maxKeys'] = $maxKeys;
        }

        return $this->sendRequest(
            HttpMethod::GET,
            array(
                'config' => $config,
                'params' => $params,
            ),
            '/blb/' . $blbId . '/HTTPSlistener'
        );
    }

    /**
     * update a tcp listener with the specified options.
     *
     * @param string $blbId
     *          id of blb
     *
     * @param int $listenerPort
     *          front end port of listener
     *
     * @param int $backendPort
     *          back end port of listener
     *
     * @param string $scheduler
     *          scheduler of load balance
     *
     * @param int $healthCheckTimeoutInSecond
     *          timeout of health check, default 3 seconds
     *
     * @param int $healthCheckInterval
     *          interval of health check, default 3 seconds
     *
     * @param int $unhealthyThreshold
     *          times threshold of unhealthy check, default 3 times
     *
     * @param int $healthyThreshold
     *          times threshold of healthy check, default 3 times
     *
     * @param string $clientToken
     *          if the clientToken is not specified by the user, a random String
     *          generated by default algorithm will be used.
     *
     * @param array $options
     *          The optional bce configuration, which will overwrite the
     *          default configuration that was passed while creating EipClient instance.
     *
     * @return mixed
     */
    public function updateTcpListener($blbId, $listenerPort, $backendPort = null, $scheduler = null, $healthCheckTimeoutInSecond = null, $healthCheckInterval = null, $unhealthyThreshold = null, $healthyThreshold = null, $clientToken = null, $options = array())
    {
        list($config) = $this->parseOptions($options, 'config');
        $body = array();
        if ($backendPort !== null) {
            $body['backendPort'] = $backendPort;
        }
        if ($scheduler !== null) {
            $body['scheduler'] = $scheduler;
        }
        if ($healthCheckTimeoutInSecond !== null) {
            $body['healthCheckTimeoutInSecond'] = $healthCheckTimeoutInSecond;
        }
        if ($healthCheckInterval !== null) {
            $body['healthCheckInterval'] = $healthCheckInterval;
        }
        if ($unhealthyThreshold !== null) {
            $body['unhealthyThreshold'] = $unhealthyThreshold;
        }
        if ($healthyThreshold !== null) {
            $body['healthyThreshold'] = $healthyThreshold;
        }
        $body['end'] = '';
        $params = array();
        $params['listenerPort'] = $listenerPort;
        if (empty($clientToken)) {
            $params['clientToken'] = $this->generateClientToken();
        } else {
            $params['clientToken'] = $clientToken;
        }

        return $this->sendRequest(
            HttpMethod::PUT,
            array(
                'config' => $config,
                'params' => $params,
                'body' => json_encode($body),
            ),
            '/blb/' . $blbId . '/TCPlistener'
        );
    }

    /**
     * update a udp listener with the specified options.
     *
     * @param string $blbId
     *          id of blb
     *
     * @param int $listenerPort
     *          front end port of listener
     *
     * @param int $backendPort
     *          back end port of listener
     *
     * @param string $scheduler
     *          scheduler of load balance
     *
     * @param string $healthCheckString
     *          string to send for health check
     *
     * @param int $healthCheckTimeoutInSecond
     *          timeout of health check, default 3 seconds
     *
     * @param int $healthCheckInterval
     *          interval of health check, default 3 seconds
     *
     * @param int $unhealthyThreshold
     *          times threshold of unhealthy check, default 3 times
     *
     * @param int $healthyThreshold
     *          times threshold of healthy check, default 3 times
     *
     * @param string $clientToken
     *          if the clientToken is not specified by the user, a random String
     *          generated by default algorithm will be used.
     *
     * @param array $options
     *          The optional bce configuration, which will overwrite the
     *          default configuration that was passed while creating EipClient instance.
     *
     * @return mixed
     */
    public function updateUdpListener($blbId, $listenerPort, $backendPort, $scheduler, $healthCheckString, $healthCheckTimeoutInSecond = null, $healthCheckInterval = null, $unhealthyThreshold = null, $healthyThreshold = null, $clientToken = null, $options = array())
    {
        list($config) = $this->parseOptions($options, 'config');
        $body = array();
        $body['backendPort'] = $backendPort;
        $body['scheduler'] = $scheduler;
        $body['healthCheckString'] = $healthCheckString;
        if ($healthCheckTimeoutInSecond !== null) {
            $body['healthCheckTimeoutInSecond'] = $healthCheckTimeoutInSecond;
        }
        if ($healthCheckInterval !== null) {
            $body['healthCheckInterval'] = $healthCheckInterval;
        }
        if ($unhealthyThreshold !== null) {
            $body['unhealthyThreshold'] = $unhealthyThreshold;
        }
        if ($healthyThreshold !== null) {
            $body['healthyThreshold'] = $healthyThreshold;
        }
        $body['end'] = '';
        $params = array();
        $params['listenerPort'] = $listenerPort;
        if (empty($clientToken)) {
            $params['clientToken'] = $this->generateClientToken();
        } else {
            $params['clientToken'] = $clientToken;
        }

        return $this->sendRequest(
            HttpMethod::PUT,
            array(
                'config' => $config,
                'params' => $params,
                'body' => json_encode($body),
            ),
            '/blb/' . $blbId . '/UDPlistener'
        );
    }

    /**
     * update a http listener with the specified options.
     *
     * @param string $blbId
     *          id of blb
     *
     * @param int $listenerPort
     *          front end port of listener
     *
     * @param int $backendPort
     *          back end port of listener
     *
     * @param string $scheduler
     *          scheduler of load balance
     *
     * @param boolean $keepSession
     *          switch for keep session
     *
     * @param string $keepSessionType
     *          type to keep session
     *
     * @param int $keepSessionDuration
     *          duration to keep session
     *
     * @param string $keepSessionCookieName
     *          cookie name for keep session
     *
     * @param boolean $xForwardFor
     *          switch for acquiring real ip
     *
     * @param string $healthCheckType
     *          type for health check
     *
     * @param int $healthCheckPort
     *          port for health check
     *
     * @param string $healthCheckURI
     *          uri for health check
     *
     * @param int $healthCheckTimeoutInSecond
     *          timeout of health check, default 3 seconds
     *
     * @param int $healthCheckInterval
     *          interval of health check, default 3 seconds
     *
     * @param int $unhealthyThreshold
     *          times threshold of unhealthy check, default 3 times
     *
     * @param int $healthyThreshold
     *          times threshold of healthy check, default 3 times
     *
     * @param string $healthCheckNormalStatus
     *          normal status for http health check
     *
     * @param int $serverTimeout
     *          timeout for backend server
     *
     * @param int $redirectPort
     *          port for redirect
     *
     * @param string $clientToken
     *          if the clientToken is not specified by the user, a random String
     *          generated by default algorithm will be used.
     *
     * @param array $options
     *          The optional bce configuration, which will overwrite the
     *          default configuration that was passed while creating EipClient instance.
     *
     * @return mixed
     */
    public function updateHttpListener($blbId, $listenerPort, $backendPort = null, $scheduler = null, $keepSession = null,
                                       $keepSessionType = null, $keepSessionDuration = null, $keepSessionCookieName = null,
                                       $xForwardFor = null, $healthCheckType = null, $healthCheckPort = null, $healthCheckURI = null,
                                       $healthCheckTimeoutInSecond = null, $healthCheckInterval = null, $unhealthyThreshold = null, $healthyThreshold = null,
                                       $healthCheckNormalStatus = null, $serverTimeout = null, $redirectPort = null, $clientToken = null, $options = array())
    {
        list($config) = $this->parseOptions($options, 'config');
        $body = array();
        if ($backendPort !== null) {
            $body['backendPort'] = $backendPort;
        }
        if ($scheduler !== null) {
            $body['scheduler'] = $scheduler;
        }
        if ($keepSession !== null) {
            $body['keepSession'] = $keepSession;
        }
        if ($keepSessionType !== null) {
            $body['keepSessionType'] = $keepSessionType;
        }
        if ($keepSessionDuration !== null) {
            $body['keepSessionDuration'] = $keepSessionDuration;
        }
        if ($keepSessionCookieName !== null) {
            $body['keepSessionCookieName'] = $keepSessionCookieName;
        }
        if ($xForwardFor !== null) {
            $body['xForwardFor'] = $xForwardFor;
        }
        if ($healthCheckType !== null) {
            $body['healthCheckType'] = $healthCheckType;
        }
        if ($healthCheckPort !== null) {
            $body['healthCheckPort'] = $healthCheckPort;
        }
        if ($healthCheckURI !== null) {
            $body['healthCheckURI'] = $healthCheckURI;
        }
        if ($healthCheckNormalStatus !== null) {
            $body['healthCheckNormalStatus'] = $healthCheckNormalStatus;
        }
        if ($serverTimeout !== null) {
            $body['serverTimeout'] = $serverTimeout;
        }
        if ($redirectPort !== null) {
            $body['redirectPort'] = $redirectPort;
        }
        if ($healthCheckTimeoutInSecond !== null) {
            $body['healthCheckTimeoutInSecond'] = $healthCheckTimeoutInSecond;
        }
        if ($healthCheckInterval !== null) {
            $body['healthCheckInterval'] = $healthCheckInterval;
        }
        if ($unhealthyThreshold !== null) {
            $body['unhealthyThreshold'] = $unhealthyThreshold;
        }
        if ($healthyThreshold !== null) {
            $body['healthyThreshold'] = $healthyThreshold;
        }
        $body['end'] = '';
        $params = array();
        $params['listenerPort'] = $listenerPort;
        if (empty($clientToken)) {
            $params['clientToken'] = $this->generateClientToken();
        } else {
            $params['clientToken'] = $clientToken;
        }

        return $this->sendRequest(
            HttpMethod::PUT,
            array(
                'config' => $config,
                'params' => $params,
                'body' => json_encode($body),
            ),
            '/blb/' . $blbId . '/HTTPlistener'
        );
    }

    /**
     * update a https listener with the specified options.
     *
     * @param string $blbId
     *          id of blb
     *
     * @param int $listenerPort
     *          front end port of listener
     *
     * @param int $backendPort
     *          back end port of listener
     *
     * @param string $scheduler
     *          scheduler of load balance
     *
     * @param array $certIds
     *          SSL certs for listener
     *
     * @param boolean $keepSession
     *          switch for keep session
     *
     * @param string $keepSessionType
     *          type to keep session
     *
     * @param int $keepSessionDuration
     *          duration to keep session
     *
     * @param string $keepSessionCookieName
     *          cookie name for keep session
     *
     * @param boolean $xForwardFor
     *          switch for acquiring real ip
     *
     * @param string $healthCheckType
     *          type for health check
     *
     * @param int $healthCheckPort
     *          port for health check
     *
     * @param string $healthCheckURI
     *          uri for health check
     *
     * @param int $healthCheckTimeoutInSecond
     *          timeout of health check, default 3 seconds
     *
     * @param int $healthCheckInterval
     *          interval of health check, default 3 seconds
     *
     * @param int $unhealthyThreshold
     *          times threshold of unhealthy check, default 3 times
     *
     * @param int $healthyThreshold
     *          times threshold of healthy check, default 3 times
     *
     * @param string $healthCheckNormalStatus
     *          normal status for http health check
     *
     * @param int $serverTimeout
     *          timeout for backend server
     *
     * @param boolean $ie6Compatible
     *          switch for compatibility with IE6
     *
     * @param string $clientToken
     *          if the clientToken is not specified by the user, a random String
     *          generated by default algorithm will be used.
     *
     * @param array $options
     *          The optional bce configuration, which will overwrite the
     *          default configuration that was passed while creating EipClient instance.
     *
     * @return mixed
     */
    public function updateHttpsListener($blbId, $listenerPort, $backendPort = null, $scheduler = null, $certIds = null, $keepSession = null,
                                        $keepSessionType = null, $keepSessionDuration = null, $keepSessionCookieName = null,
                                        $xForwardFor = null, $healthCheckType = null, $healthCheckPort = null, $healthCheckURI = null,
                                        $healthCheckTimeoutInSecond = null, $healthCheckInterval = null, $unhealthyThreshold = null, $healthyThreshold = null,
                                        $healthCheckNormalStatus = null, $serverTimeout = null, $ie6Compatible = null, $clientToken = null, $options = array())
    {
        list($config) = $this->parseOptions($options, 'config');
        $body = array();
        if ($backendPort !== null) {
            $body['backendPort'] = $backendPort;
        }
        if ($scheduler !== null) {
            $body['scheduler'] = $scheduler;
        }
        if ($certIds !== null) {
            $body['certIds'] = $this->objectToArray($certIds);
        }
        if ($keepSession !== null) {
            $body['keepSession'] = $keepSession;
        }
        if ($keepSessionType !== null) {
            $body['keepSessionType'] = $keepSessionType;
        }
        if ($keepSessionDuration !== null) {
            $body['keepSessionDuration'] = $keepSessionDuration;
        }
        if ($keepSessionCookieName !== null) {
            $body['keepSessionCookieName'] = $keepSessionCookieName;
        }
        if ($xForwardFor !== null) {
            $body['xForwardFor'] = $xForwardFor;
        }
        if ($healthCheckType !== null) {
            $body['healthCheckType'] = $healthCheckType;
        }
        if ($healthCheckPort !== null) {
            $body['healthCheckPort'] = $healthCheckPort;
        }
        if ($healthCheckURI !== null) {
            $body['healthCheckURI'] = $healthCheckURI;
        }
        if ($healthCheckNormalStatus !== null) {
            $body['healthCheckNormalStatus'] = $healthCheckNormalStatus;
        }
        if ($serverTimeout !== null) {
            $body['serverTimeout'] = $serverTimeout;
        }
        if ($ie6Compatible !== null) {
            $body['ie6Compatible'] = $ie6Compatible;
        }
        if ($healthCheckTimeoutInSecond !== null) {
            $body['healthCheckTimeoutInSecond'] = $healthCheckTimeoutInSecond;
        }
        if ($healthCheckInterval !== null) {
            $body['healthCheckInterval'] = $healthCheckInterval;
        }
        if ($unhealthyThreshold !== null) {
            $body['unhealthyThreshold'] = $unhealthyThreshold;
        }
        if ($healthyThreshold !== null) {
            $body['healthyThreshold'] = $healthyThreshold;
        }
        $body['end'] = '';
        $params = array();
        $params['listenerPort'] = $listenerPort;
        if (empty($clientToken)) {
            $params['clientToken'] = $this->generateClientToken();
        } else {
            $params['clientToken'] = $clientToken;
        }

        return $this->sendRequest(
            HttpMethod::PUT,
            array(
                'config' => $config,
                'params' => $params,
                'body' => json_encode($body),
            ),
            '/blb/' . $blbId . '/HTTPSlistener'
        );
    }

    /**
     * delete a listener.
     *
     * @param string $blbId
     *          id of blb
     *
     * @param array $portList
     *          ports of listener to be deleted
     *
     * @param string $clientToken
     *          if the clientToken is not specified by the user, a random String
     *          generated by default algorithm will be used.
     *
     * @param array $options
     *          The optional bce configuration, which will overwrite the
     *          default configuration that was passed while creating EipClient instance.
     *
     * @return mixed
     */
    public function deleteListeners($blbId, $portList, $clientToken = null, $options = array())
    {
        list($config) = $this->parseOptions($options, 'config');
        $body = array();
        $body['portList'] = $this->objectToArray($portList);
        $params = array();
        $params['batchdelete'] = '';
        if (empty($clientToken)) {
            $params['clientToken'] = $this->generateClientToken();
        } else {
            $params['clientToken'] = $clientToken;
        }

        return $this->sendRequest(
            HttpMethod::PUT,
            array(
                'config' => $config,
                'params' => $params,
                'body' => json_encode($body),
            ),
            '/blb/' . $blbId . '/listener'
        );
    }

    /**
     * add backend server
     *
     * @param string $blbId
     *          blb instance id
     *
     * @param array $backendServerList
     *          back end servers to be added
     *
     * @param string $clientToken
     *          if the clientToken is not specified by the user, a random String
     *          generated by default algorithm will be used.
     *
     * @param array $options
     *          The optional bce configuration, which will overwrite the
     *          default configuration that was passed while creating EipClient instance.
     *
     * @return mixed
     */
    public function addBackendServer($blbId, $backendServerList, $clientToken = null, $options = array())
    {
        list($config) = $this->parseOptions($options, 'config');
        $body = array();
        $body['backendServerList'] = $this->objectToArray($backendServerList);
        $params = array();
        if (empty($clientToken)) {
            $clientToken = $this->generateClientToken();
        }
        $params['clientToken'] = $clientToken;
        return $this->sendRequest(
            HttpMethod::POST,
            array(
                'config' => $config,
                'params' => $params,
                'body' => json_encode($body),
            ),
            '/blb/' . $blbId . '/backendserver'
        );
    }

    /**
     * list backend servers mounted with blb instance. Health Status will be presented while listener port is necessary
     *
     * @param string $blbId
     *          blb instance id
     *
     * @param int listenerPort
     *          port of listener
     *
     * @param string $marker
     *          The optional parameter marker specified in the original request to specify
     *          where in the results to begin listing.
     *
     * @param int $maxKeys
     *          The optional parameter to specifies the max number of list result to return.
     *          The default value is 1000.
     *
     * @param string $clientToken
     *          if the clientToken is not specified by the user, a random String
     *          generated by default algorithm will be used.
     *
     * @param array $options
     *          The optional bce configuration, which will overwrite the
     *          default configuration that was passed while creating EipClient instance.
     *
     * @return mixed
     */
    public function listBackendServersWithPort($blbId, $listenerPort, $marker = null, $maxKeys = 1000, $clientToken = null, $options = array())
    {
        list($config) = $this->parseOptions($options, 'config');
        $params = array();
        if (empty($clientToken)) {
            $clientToken = $this->generateClientToken();
        }
        $params['clientToken'] = $clientToken;
        $params['listenerPort'] = $listenerPort;
        if ($marker !== null) {
            $params['marker'] = $marker;
        }
        if ($maxKeys !== null) {
            $params['maxKeys'] = $maxKeys;
        }
        return $this->sendRequest(
            HttpMethod::GET,
            array(
                'config' => $config,
                'params' => $params,
            ),
            '/blb/' . $blbId . '/backendserver'
        );
    }

    /**
     * list backend servers mounted with blb instance
     *
     * @param string $blbId
     *          blb instance id
     *
     * @param string $marker
     *          The optional parameter marker specified in the original request to specify
     *          where in the results to begin listing.
     *
     * @param int $maxKeys
     *          The optional parameter to specifies the max number of list result to return.
     *          The default value is 1000.
     *
     * @param string $clientToken
     *          if the clientToken is not specified by the user, a random String
     *          generated by default algorithm will be used.
     *
     * @param array $options
     *          The optional bce configuration, which will overwrite the
     *          default configuration that was passed while creating EipClient instance.
     *
     * @return mixed
     */
    public function listBackendServers($blbId, $marker = null, $maxKeys = 1000, $clientToken = null, $options = array())
    {
        list($config) = $this->parseOptions($options, 'config');
        $params = array();
        if (empty($clientToken)) {
            $clientToken = $this->generateClientToken();
        }
        $params['clientToken'] = $clientToken;
        if ($marker !== null) {
            $params['marker'] = $marker;
        }
        if ($maxKeys !== null) {
            $params['maxKeys'] = $maxKeys;
        }
        return $this->sendRequest(
            HttpMethod::GET,
            array(
                'config' => $config,
                'params' => $params,
            ),
            '/blb/' . $blbId . '/backendserver'
        );
    }

    /**
     * update weight of backend servers
     *
     * @param string $blbId
     *          blb instance id
     *
     * @param array $backendServerList
     *          back end servers to be updated
     *
     * @param string $clientToken
     *          if the clientToken is not specified by the user, a random String
     *          generated by default algorithm will be used.
     *
     * @param array $options
     *          The optional bce configuration, which will overwrite the
     *          default configuration that was passed while creating EipClient instance.
     *
     * @return mixed
     */
    public function updateBackendServer($blbId, $backendServerList, $clientToken = null, $options = array())
    {
        list($config) = $this->parseOptions($options, 'config');
        $body = array();
        $body['backendServerList'] = $this->objectToArray($backendServerList);
        $params = array();
        if (empty($clientToken)) {
            $clientToken = $this->generateClientToken();
        }
        $params['clientToken'] = $clientToken;
        $params['update'] = '';
        return $this->sendRequest(
            HttpMethod::PUT,
            array(
                'config' => $config,
                'params' => $params,
                'body' => json_encode($body),
            ),
            '/blb/' . $blbId . '/backendserver'
        );
    }

    /**
     * remove backend servers
     *
     * @param string $blbId
     *          blb instance id
     *
     * @param array $backendServerList
     *          back end servers to be removed
     *
     * @param string $clientToken
     *          if the clientToken is not specified by the user, a random String
     *          generated by default algorithm will be used.
     *
     * @param array $options
     *          The optional bce configuration, which will overwrite the
     *          default configuration that was passed while creating EipClient instance.
     *
     * @return mixed
     */
    public function removeBackendServers($blbId, $backendServerList, $clientToken = null, $options = array())
    {
        list($config) = $this->parseOptions($options, 'config');
        $body = array();
        $body['backendServerList'] = $this->objectToArray($backendServerList);
        if (empty($clientToken)) {
            $clientToken = $this->generateClientToken();
        }
        $params = array();
        $params['clientToken'] = $clientToken;

        return $this->sendRequest(
            HttpMethod::PUT,
            array(
                'config' => $config,
                'params' => $params,
                'body' => json_encode($body),
            ),
            '/blb/' . $blbId . '/backendserver'
        );
    }

    /**
     * convert object to array
     *
     * @param object $obj
     *
     * @return array
     */
    function objectToArray($obj)
    {
        if (is_array($obj)) {
            return $obj;
        }
        $_arr = is_object($obj) ? get_object_vars($obj) : $obj;
        $arr = array();
        foreach ($_arr as $key => $value) {
            $value = (is_array($value)) || is_object($value) ? $this->objectToArray($value) : $value;
            $arr[$key] = $value;
        }
        return $arr;
    }

    /**
     * Create HttpClient and send request
     *
     * @param string $httpMethod
     *          The Http request method
     *
     * @param array $varArgs
     *          The extra arguments
     *
     * @param string $requestPath
     *          The Http request uri
     *
     * @return mixed The Http response and headers.
     */
    private function sendRequest($httpMethod, array $varArgs, $requestPath = '/')
    {
        $defaultArgs = array(
            'config' => array(),
            'body' => null,
            'headers' => array(),
            'params' => array(),
        );

        $args = array_merge($defaultArgs, $varArgs);
        if (empty($args['config'])) {
            $config = $this->config;
        } else {
            $config = array_merge(
                array(),
                $this->config,
                $args['config']
            );
        }
        if (!isset($args['headers'][HttpHeaders::CONTENT_TYPE])) {
            $args['headers'][HttpHeaders::CONTENT_TYPE] = HttpContentTypes::JSON;
        }
        $path = $this->prefix . $requestPath;
        $response = $this->httpClient->sendRequest(
            $config,
            $httpMethod,
            $path,
            $args['body'],
            $args['headers'],
            $args['params'],
            $this->signer
        );

        $result = $this->parseJsonResult($response['body']);

        return $result;
    }

    /**
     * The default method to generate the random String for clientToken if the optional parameter clientToken
     * is not specified by the user.
     *
     * The default algorithm is Mersenne Twister to generate a random UUID,
     * @return String An random String generated by Mersenne Twister.
     */
    public static function generateClientToken()
    {
        $uuid = md5(uniqid(mt_rand(), true));
        return $uuid;
    }
}